﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using AlgoTest;

namespace ConsoleTest
{

    struct s
    {
        private int Test()
        {
            return 0;
        }

    }


    public interface ITest
    {
        void DoSomething();
    }

    public class InterfaceTest : ITest
    {
        private int _i;

        public void DoSomething()
        {
            _i++;
        }
    }


    class Parent
    {
        public Parent()
        {
            this.CtorTest();
        }

        ~Parent()
        {
            this.DtorTest(0);
        }

        protected virtual void CtorTest()
        {
            Console.WriteLine("Parent::CtorTest()");
        }

        protected virtual void DtorTest(int i)
        {
            Console.WriteLine("Parent::DtorTest({0})", i);
        }
    }

    class Child : Parent
    {
        ~Child()
        {
            this.DtorTest(1);
        }

        protected override void CtorTest()
        {
            Console.WriteLine("Child::CtorTest()");
        }

        protected override void DtorTest(int i)
        {
            Console.WriteLine("Child::DtorTest({0})", i);
        }
    }


    public class Singleton
    {
        public int I { get; private set; }

        private Singleton(int i)
        {
            this.I = i;
        }

        public static Singleton Instance = new Singleton(123);
    }


    static class Program
    {

        public static void InterfaceTest()
        {
            var it = new InterfaceTest();
            ITest iIt = it;

            int listSize = 30000000;
            var list = new int[listSize];

            var stw = new Stopwatch();
            stw.Start();

            int buf;
            for (int i = 0; i < listSize; i++)
            {
                it.DoSomething();

                //                buf = list[i];
                //                list[i] = list[i] + i;
            }

            stw.Stop();
            Console.WriteLine("As array: " + stw.ElapsedMilliseconds);


            IList<int> iList = list;

            stw.Reset();
            stw.Start();

            for (int i = 0; i < listSize; i++)
            {
                iIt.DoSomething();

                //                buf = iList[i];
                //                iList[i] = iList[i] + i;
            }

            stw.Stop();
            Console.WriteLine("Via interface: " + stw.ElapsedMilliseconds);

        }



        private static HashSet<int> setPushed = new HashSet<int>(), setPopped = new HashSet<int>();
        private static Random rand = new Random((int)DateTime.Now.Ticks);

        private static int finishedThreads = 0;

        static void PushValue(NonBlockingQueue q)
        {
            int value = rand.Next();

            lock (setPushed)
            {
                if (setPushed.Contains(value))
                    return;

                setPushed.Add(value);
            }

            ((NonBlockingQueue)q).Enqueue(value);
        }

        static void PushValues(object q)
        {
            for (int i = 0; i < 456; i++)
            {
//                Thread.Sleep(0);

                PushValue((NonBlockingQueue)q);
            }

            Interlocked.Increment(ref finishedThreads);
        }

        static void PopValue(object q)
        {
            try
            {
                int value = ((NonBlockingQueue) q).Dequeue();
                lock (setPopped)
                    setPopped.Add(value);
            }
            catch
            {
            }
        }

        static void PopValues(object q)
        {
            for (int i = 0; i < 456; i++)
            {
//                Thread.Sleep(0);
                PopValue(q);
            }
        }


        private static int count;

        static void TestHandler()
        {
            Console.WriteLine("Test Handler");
            Interlocked.Increment(ref count);
        }


        private static DateTime _startTime = DateTime.Now;


        static long MyCall(int a, string b)
        {
            var elapsed = DateTime.Now - _startTime;
            Console.WriteLine("Started: " + (int)elapsed.TotalMilliseconds);

            // эмулируем деятельность от 500 до 1500 мс
            long msDelay = _rnd.Next(500, 1500);

            if (msDelay % 4 == 0)
                msDelay = 1500;
            else
                msDelay = 500;

            Thread.Sleep((int)msDelay);

            Console.WriteLine("\tIt took: " + msDelay);

            elapsed = DateTime.Now - _startTime;
//            Console.WriteLine("\tFinished: " + (int)elapsed.TotalMilliseconds);

            return msDelay;
        }




        static readonly string testString = new string('a', 10000);

        static Regex MakeTestRe()
        {
            return new Regex(@"\d{2}", RegexOptions.Compiled);
        }


        static Regex DoWork(int idx, Regex re)
        {
//            Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId);

//            re.Match(testString, 0, 50);

            if (string.IsNullOrEmpty(Thread.CurrentThread.Name))
            {
                Thread.CurrentThread.Name = new string((char) _rnd.Next('a', 'z'), 1000);
            }

            var str = Thread.CurrentThread.Name; //new string((char)_rnd.Next('a', 'z'), 10000);

//            Console.WriteLine(str);
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//            re.Match(str, 0, 50);/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            return re;
        }


        public static void Foo(int[,] array)
        {
            if (array != null)
            {
                long lowerBound = array.GetLowerBound(0);
                long upperBound = array.GetUpperBound(0);
                long length = array.GetLength(0);
                if (lowerBound + length != upperBound + 1)
                {
                    Console.WriteLine("Huh?");
                }
            }
        }


        private static int StartCount = 0;
        private static int EndCount = 0;

        static void ThreadRoutine(object readerWriterTest)
        {
            var rwt = (ReaderWriterTest) readerWriterTest;

//            Thread.SpinWait(ReaderWriterTest.Rnd.Next(1000000) );

//            Thread.Sleep(ReaderWriterTest.Rnd.Next(0, 15000));
            try
            {
                int atStart = Interlocked.Increment(ref StartCount);

                int res = rwt.CalculateOrderCost();

                int atEnd = Interlocked.Increment(ref EndCount);

                Console.WriteLine("{0} - {1} - {2}", atEnd, atStart, res);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private static Random _rnd = new Random(DateTime.Now.Millisecond);

        static long SortTest(Action<int[]> sortRoutine, int numOfTries, int arraySize, int minValue, int maxValue)
        {
            var list = new List<int>();

            var sw = new Stopwatch();
            long elapsedMs = 0;

            for (int i = 0; i < numOfTries; i++)
            {
                list.Clear();
                for (int j = 0; j < arraySize; j++)
                    list.Add(_rnd.Next(minValue, maxValue));

//                for (int j = arraySize; j > 0; j--)
//                    list.Add(j);


                var array = list.ToArray();

                sw.Start();

                sortRoutine(array);

                sw.Stop();
                elapsedMs += sw.ElapsedMilliseconds;
                sw.Reset();

                if (!array.IsSorted())
                    throw new Exception("Not sorted!");
            }

            return elapsedMs / numOfTries;
        }



        private static IEnumerable<char> FromConsole
        {
            get
            {
                var c = Console.ReadKey();
                while (c.Key != ConsoleKey.Enter)
                {
                    yield return c.KeyChar;
                    c = Console.ReadKey();
                }
            }
        }

        static string ReverseString(string str)
        {
            return new string( str.Reverse().ToArray());
        }


        static void ReverseWordTest()
        {
            string res = FromConsole.AsStringBuilder().ReverseWords();

            Console.WriteLine();
            Console.WriteLine(res);
        }


        static string ConvertToString(this int val)
        {
            var res = new StringBuilder();

            while(val > 0)
            {
                int rem;
                val = Math.DivRem(val, 10, out rem);

                res.Insert(0, (char) ('0' + (char) rem));
            }
            return res.ToString();
        }

        static void TreeTest()
        {
            var root = new TreeNode<int>(){Value = 1};

            root.Left = new TreeNode<int>(){Value = 2};
            root.Right = new TreeNode<int>() { Value = 3 };

            root.Left.Left = new TreeNode<int>() { Value = 4 };
            root.Right.Left = new TreeNode<int>() { Value = 5 };
            
            foreach(var v in root.AsEnumerable())
            {
                Console.WriteLine(v.ToString());
            }
        }

        static void StackQueueTest()
        {
            var q = new StackQueue<int>();

            q.Push(1);
            q.Push(2);
            Console.WriteLine(q.Pop());
            q.Push(3);
            q.Push(4);
            Console.WriteLine(q.Pop());
            Console.WriteLine(q.Pop());
            q.Push(5);

            Console.WriteLine(q.Pop());
            Console.WriteLine(q.Pop());
        }

        static void RandomHeapTest()
        {
            var rnd = new Random(DateTime.Now.Millisecond);

            var heap = new RandomHeap<int>();

            for(int i = 0; i < 10; i++)
            {
                heap.Add(rnd.Next(0, 100));
            }

            var list = new List<int>();

            heap.Traverse(list);

            foreach (var v in list)
            {
                Console.WriteLine(v);
            }
        }

        static void BankomatTestTest()
        {
            var bt = new BankomatTest(6);

            foreach (var b in bt.Withdraw())
            {
                Console.WriteLine(b);
            }
        }

        static void HighestNodeTest()
        {
/*
            var root = new HighestNode.Node()
            {
                item = 10,
                left = new HighestNode.Node()
                {
                    item = 5,
                    left = new HighestNode.Node()
                    {
                        item = 2
                    },
                    right = new HighestNode.Node()
                    {
                        item = 7
                    }
                },
                right = new HighestNode.Node()
                {
                    item = 14,
                    left = new HighestNode.Node()
                    {
                        item = 12
                    },
                }
            };

            var root = new HighestNode.Node()
            {
                item = 10,
                left = new HighestNode.Node()
                {
                    item = 8,
                    left = new HighestNode.Node()
                    {
                        item = 6
                    },
                }
            };
*/

            var root = new HighestNode.Node()
            {
                item = 10,
                right = new HighestNode.Node()
                {
                    item = 12,
                    right = new HighestNode.Node()
                    {
                        item = 14
                    },
                }
            };

            var res = HighestNode.FindNextHighest(root, 10);

            Console.WriteLine(res != null ? res.item.ToString() : "null");
        }


        static void LuxoftTestTest()
        {
            
        }



        private static volatile int check = 0;



        struct STest
        {
            public int i;

            public int Change()
            {
                i = i + 1;

                return i;
            }
        }

        class Test
        {
//            public DateTime _dt = DateTime.Now;

            public STest s = new STest();
        }



        static void Main(string[] args)
        {
            var t1 = Task.Factory.StartNew(ProducerConsumerSemaphoreTest.Producer);
            var t2 = Task.Factory.StartNew(ProducerConsumerSemaphoreTest.Consumer);

            t1.Wait();
            t2.Wait();

            return;


            var cs = new EventCriticalSection();

            cs.Enter();
            cs.Exit();
            cs.Enter();

            var taskList = new List<Task>();

            for (int i = 0; i < 3; i++)
            {
                int ii = i;

                Thread.Sleep(30);

                var t = Task.Factory.StartNew(() =>
                {
                    int k = 1;
                    while (true)
                    {
                        if (k%10000 == 0)
                        {
                            Console.WriteLine("Hi from task {0}", ii);
                        }
                        k++;


                        cs.Enter();

                        if (check != 0)
                        {
                            Console.WriteLine("Oops... check != 0");
                        }
                        check++;

                        Thread.Sleep(0);

                        if (check != 1)
                        {
                            Console.WriteLine("Oops... check != 1");
                        }
                        check--;

                        Thread.Sleep(0);

                        if (check != 0)
                        {
                            Console.WriteLine("Oops... check != 0 at the end");
                        }

                        cs.Exit();
                    }
                });

                taskList.Add(t);
            }

            Thread.Sleep(5000);

            cs.Exit();


            Task.WaitAll(taskList.ToArray());

            return;







            var evt = new ManualResetEvent(false);

            Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        evt.WaitOne();

                        Console.WriteLine("a");
                    }
                    
                });

            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    evt.WaitOne();

                    Console.WriteLine("b");
                }

            });


            var key = Console.ReadKey();
            while (key.Key != ConsoleKey.Enter)
            {
                if (key.Key == ConsoleKey.Spacebar)
                {
                    evt.Set();
                }
                else
                {
                    evt.Reset();
                }

                key = Console.ReadKey();
            }

            return;



            {
                Parent p = new Child();
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Console.ReadKey();
            return;


//            HighestNodeTest();

//            int i = 123450;
//            Console.WriteLine(i.ConvertToString());



//            var list = Node.FromList(new [] {1, 2, 3, 4});

            // тест поиска точки начала цикла
//            list.Last.Next = list.Find(2);
//            Console.WriteLine(list.FindCycleStart().Value);


/*          тест слияния сортированных списков
            var list1 = Node.FromList(new[] { 1, 3, 7, 8, 9 });
            var list2 = Node.FromList(new[] { 2, 4, 5, 6 });

            var sortedList = Node.SortMerge(list1, list2);
            
            Console.WriteLine(string.Concat(sortedList.AsEnumerable()));
*/
            
//            list = list.Reverse();
//            Console.WriteLine(string.Concat(list.AsEnumerable()));




            Console.ReadKey();
            return;

/*
            string res = FromConsole.AsReversePolish().AsString();

            Console.WriteLine();
            Console.WriteLine(res);

            Console.ReadKey();
            return;

            string pattern = "abb*ed";

            var parts = pattern.Split('*');

            var list1 = new List<string>
                            {
                                "abalienated",
                                "abbandoned",
                                "abbacinare",
                                "abbreviated",
                                "ablastemic"
                            };


            list1.Sort();

            foreach (var s in list1)
                Console.WriteLine(s);

            Console.WriteLine();

            var list2 = new List<string>();

            foreach (var s in list1)
            {
                if (s.Substring(0, parts[0].Length) == parts[0])
                    list2.Add(s);
            }

            list2.Sort((s1, s2) => string.Compare(ReverseString(s1), ReverseString(s2)) );

            foreach (var s in list2)
                Console.WriteLine(s);

            Console.WriteLine();
*/

/*
            using(var r = new StreamReader("c:\\test.txt"))
            {
                using(var w = new StreamWriter("c:\\result.txt"))
                {
                    w.Write( new StringBuilder(r.ReadToEnd()).ReverseWords());
                }
            }

            var sb = new StringBuilder();
            var sb2 = sb;

            if(sb == sb2)
            {
                
            }
 */ 



/*
            int arraySize = 20000000;
            int minValue = int.MinValue;
            int maxValue = int.MaxValue;

            var ms = SortTest(list => list.ParallelSort(), 3, arraySize, minValue, maxValue);
//            var ms = SortTest(list => list.RadixSort(), 3, arraySize, minValue, maxValue);
//            var ms = SortTest(Array.Sort, 3, arraySize, minValue, maxValue);

            Console.WriteLine("Sorted in " + ms);
*/




/*
            var rwt = new ReaderWriterTest();



            var threadList = new List<Thread>();

            var key = Console.ReadKey();
            while(key.Key != ConsoleKey.Spacebar)
            {
                var t = new Thread(ThreadRoutine);
                t.Name += key.KeyChar;
                t.Start(rwt);
                threadList.Add(t);

                key = Console.ReadKey();
            }

            foreach (var t in threadList)
                t.Join();
*/
            Console.WriteLine("Finished");

/*
            var list = new List<int>();

            var rnd = new Random(DateTime.Now.Millisecond);

            int prevA = rnd.Next(0, 2);
            int curA = 0;

            int i = 0;
            while(i < 100000)
            {
                curA = rnd.Next(0, 2);

                if((prevA == 1) && (curA == 1))
                {
                }
                else if((prevA == 0) && (curA == 0))
                {
                    list.Add(1);
                    i++;
                }
                else
                {
                    list.Add(0);
                    i++;
                }

                prevA = curA;
            }

            var s = list.Count(k => k == 1);

            Console.WriteLine(s);
*/
//            Console.ReadKey();

//            Console.WriteLine("Call count: " + ReaderWriterTest.CallCount);

            Console.ReadKey();
            return;

/*
            var ctx = new TEST_DBEntities();

            int i = 0;
            for (var dt = dateBegin; dt < dateEnd; dt += TimeSpan.FromSeconds(1))
            {
                var t = new Table();
                t.ID = 208;
                t.Date = dt;
                t.VALUE = i++;
                ctx.Table.AddObject(t);

                if (i % 100 == 0)
                    ctx.SaveChanges();
            }

            ctx.SaveChanges();

            Console.WriteLine("Main Thread: " + Thread.CurrentThread.ManagedThreadId);

            using(var activeObject = new ActiveObject2())
            {
                activeObject.InvokeAsync(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                                                   Thread.Sleep(100); });
//                Thread.Sleep(1000);
                activeObject.InvokeAsync(() => Console.WriteLine(Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(1000);
                activeObject.InvokeAsync(() => Console.WriteLine(Thread.CurrentThread.ManagedThreadId));
            }
*/
/*
            var call1 = new AsyncCall<string>(s => Console.WriteLine(s));

            for (int i = 0; i < 10; i++)
            {
                call1.Post(i.ToString());
            }

            Thread.Sleep(3000);

            for (int i = 10; i < 20; i++)
            {
                call1.Post(i.ToString());
            }
*/

/*
            using(var activeObject = new ActiveObject())
            {
                activeObject.InvokeAsync(() => Console.WriteLine(DateTime.Now));
                Thread.Sleep(1000);
                activeObject.InvokeAsync(() => Console.WriteLine(DateTime.Now));
                Thread.Sleep(1000);

                Console.WriteLine("end of using");
            }

            Console.WriteLine("end of Main()");
*/

/*
            var t = new EventTest();

            new Thread(() =>
            {
                for(var i = 0; i < 10000; i++)
                {
                    t.SomeEvent += TestHandler;
                    Thread.Sleep(1);
                    t.SomeEvent -= TestHandler;
                }
                               
            }).Start();

            new Thread(() =>
            {
                for (var i = 0; i < 10000; i++)
                    t.Raise();

                Console.WriteLine("Handled: " + count);
            }).Start();
*/


/*
            int i = -20;

            for(int j = 0; j < 50; j++)
            {
                UInt32 index = (UInt32)Interlocked.Increment(ref i);
                Console.WriteLine(i.ToString() + " " + (index % 14).ToString());
            }
*/
/*
            var q = new NonBlockingQueue(1500);

            for (int i = 0; i < 10; i++)
                new Thread(PopValues).Start(q);

            for (int i = 0; i < 3; i++)
                new Thread(PushValues).Start(q);


            for (int i = 0; i < 1000; i++)
            {
                PushValue(q);
                PopValue(q);
            }

            Console.ReadKey();


            try
            {
                while(true)
                {
                    int value = ((NonBlockingQueue)q).Dequeue();
                    lock (setPopped)
                        setPopped.Add(value);
                }
            }
            catch
            {
            }

            bool bEquals = true;
            if (setPushed.Count == setPopped.Count)
            {
                foreach (var i in setPushed)
                {
                    if (!setPopped.Contains(i))
                    {
                        bEquals = false;
                        break;
                    }
                }
            }
            else
                bEquals = false;

            Console.WriteLine("Popped: " + setPopped.Count + "; Equals: " + bEquals);
 */

/*
            // последовательность каждую секунду
            var obsEachSecond = Observable.Interval(TimeSpan.FromMilliseconds(1000)).Take(10);
            // проецируем на нее вызов метода
            obsEachSecond.Select((l, r) => MyCall((int) l, "some param")).Subscribe(i => Console.WriteLine("It's now: " + (int)(DateTime.Now - _startTime).TotalMilliseconds));
*/


/*
            var inputData = Enumerable.Range(0, 200000);//2000000);
            Regex globalRe = MakeTestRe();

            Stopwatch sw = new Stopwatch();

            sw.Start();
            foreach (var x in inputData)
                DoWork(x, globalRe);
            sw.Stop();
            Console.WriteLine("foreach: {0}", sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            Parallel.ForEach(inputData, x => DoWork(x, globalRe));
            sw.Stop();
            Console.WriteLine("Parallel.ForEach, global regex: {0}", sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            Parallel.ForEach(inputData, MakeTestRe, (x, state, localRe) => DoWork(x, localRe), re => { });
            sw.Stop();
            Console.WriteLine("Parallel.ForEach, thread local regex: {0}", sw.ElapsedMilliseconds);
*/



            Console.WriteLine("Finished");
            Console.ReadKey();
        }
    }
}
